import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { BaseHttpService } from '../../shared/services/baseHttp.service';
import { Observable } from 'rxjs/Observable';
import { StorageService } from '../../shared/services/storage.service';
import { PortfolioFilterModel } from './models/portfolioFilter.model'
import { PortfolioModel } from './models/portfolio.model'
import { PortfolioSharingStatus } from './models/portfolioSharingStatus.model';
import { PortfolioType } from './models/portfolioType.model';
import { AnalyticsService } from '../../shared/services/googleAnalytics.service';
import { GoogleAnalyticsBeacon } from '../../shared/models/googleAnalytics.model';
import { PortfolioMonitoringStatusModel } from './models/portfolioMonitoringStatus.model';
import { Subject } from 'rxjs';
import { debug } from 'util';

export enum PortfolioUniversesType {
    'My portfolios' = 0,
    'Shared portfolios' = 1,
    'Universes' = 2,
    'System portfolios' = 3
}

/**
 * TODO: once the portfoliosubscription method is used in a more decent way, move the analytics ebacon outside this and delte the service import
 */
@Injectable()
export class PortfolioService extends BaseHttpService {
    private portfolioServiceLink: string = 'portfolioserv/api/v1/portfolios';
    private portfolioMonitoringLink: string = 'portfolioserv/api/v1/subscribetoportfolio';
    constructor(private http: HttpClient, private analyticsService: AnalyticsService) {
        super();
    }

    /**
     * Get list of Portfolio
     * @param skip Index to take from
     * @param take Number of companies to take
     * @param orderBy Name of column to order by
     * @param orderByAsc True to order ascending by the 'orderBy' column or false for descending
     */
    public getPortfolio(skip: number, take: number, orderBy: string, orderByAsc: boolean, sharingStatus: PortfolioSharingStatus, portfolioType: PortfolioType = PortfolioType.Custom): Observable<PortfolioModel[]> {
        let userInfo = StorageService.get().userInfo;

        let listOptions: any = {
            skip: skip,
            take: take,
            orderBy: orderBy,
            orderAscending: orderByAsc,
            includeAllFields: true,
            getCount: false
        };

        let params: HttpParams = new HttpParams();
        params = params.set('isMyPortfolio', 'true')
            .set('namePortfolio', "")
            .set('sharingStatus', sharingStatus.valueOf().toString())
            .set('portfolioType', portfolioType.valueOf().toString())
            .set('isNameEqual', "false")
            .set('newVersion', 'true')
            .set("userId", userInfo.userId)
            .set("accountId", userInfo.accountId);
        params = this.urlEncodeObject(listOptions, params);
        return this.http.get<PortfolioModel[]>(this.serverUrl + this.portfolioServiceLink, { params: params });
    }

    /**
     * Get number of portoflio after the input filter is applied
     * @param filters Portofolio list filter object
     */
    public getPortfolioCount(filters: PortfolioFilterModel, portfolioType: PortfolioType = PortfolioType.Custom): Observable<number> {
        let userInfo = StorageService.get().userInfo;

        let params: HttpParams = new HttpParams();
        params = params.set('isMyPortfolio', 'true')
            .set('namePortfolio', filters.namePortfolio)
            .set('sharingStatus', filters.sharingStatus.valueOf().toString())
            .set('portfolioType', portfolioType.valueOf().toString())
            .set('isNameEqual', filters.isNameEqual.toString())
            .set('newVersion', 'true')
            .set("userId", userInfo.userId)
            .set("accountId", userInfo.accountId);

        let listOptions: any = {
            includeAllFields: false,
            getCount: true
        };

        params = this.urlEncodeObject(listOptions, params);

        return this.http.get<number>(this.serverUrl + this.portfolioServiceLink, { params: params });
    }

    /**
     * Delete a portfolio
     * @param portfolioId Portfolio Id
     */
    public deletePortfolio(portfolioId: string): Observable<Object> {
        return this.http.delete(this.serverUrl + this.portfolioServiceLink + '/' + portfolioId, { responseType: 'text' });
    }

    /**
    * Delete all mathes from a portfolio import portfolio
    * @param portfolioMatchName Portfolio Match Name
    */
    public deleteAllMatches(portfolioMatchName: string): Observable<Object> {
        return this.http.delete(this.serverUrl + this.portfolioServiceLink + '/' + portfolioMatchName + "/matches/deleteAllMatches", { responseType: 'text' });
    }


    public deleteSelectedMatches(portfolioMatchIds: any[], portfolioMatch: string) /*: Observable<any> */ {
        return this.http.put(this.serverUrl + this.portfolioServiceLink + '/' + portfolioMatch + "/matches/deleteSelectedMatches", { portfolioMatchIds: portfolioMatchIds }, { responseType: 'text' });
    }

    public addSelectedMatch(portfolioMatchId: string, portfolioMatch: string): Observable<any> {
        return this.http.put(this.serverUrl + this.portfolioServiceLink + '/' + portfolioMatch + "/matches/" + portfolioMatchId, null, { responseType: 'text' });
    }

    public addCompanyToPortfolio(companyId: string, portfolioId: string): Observable<any> {
        return this.http.post(this.serverUrl + this.portfolioServiceLink + '/' + portfolioId + "/details/" + companyId, null, { responseType: 'text' });
    }
    public addSecurityToNewPortfolio(companyId: string, portfolioId: string) {
        return this.http.post(this.serverUrl + this.portfolioServiceLink + '/' + portfolioId + "/matches/addCompany/" + companyId, null, { responseType: 'text' });
    }

    public deleteCompanyFromPortfolio(portfolioId: string, securityId: string): Observable<Object> {
        return this.http.delete(this.serverUrl + this.portfolioServiceLink + '/' + portfolioId + "/details/" + securityId, { responseType: 'text' });
    }

    public updatePortfolioName(portfolioId: string, portfolioNewName: string) {
        let params: HttpParams = new HttpParams();
        params = params.set("id", portfolioId)
            .set("newName", portfolioNewName);
        return this.http.patch(this.serverUrl + this.portfolioServiceLink, null, { params: params, responseType: 'text' });
    }

    public getPortfolioMonitoring(userId: string, accountId: string, getAll: boolean = false, getOnlyAutomaticSystemPorfolios?: boolean): Observable<PortfolioMonitoringStatusModel> {
        let ret: Subject<any> = new Subject<any>();
        let params: HttpParams = new HttpParams();
        params = params.set("userId", userId)
            .set("accountId", accountId);
        if (getAll == true)
            params = params.set('getAllPortfolios', getAll.toString());
        if (getOnlyAutomaticSystemPorfolios != undefined)
            params = params.set('getOnlyAutomaticSystemPorfolios', getOnlyAutomaticSystemPorfolios.toString());

        this.http.get<any>(this.serverUrl + this.portfolioMonitoringLink, { params: params }).subscribe(response => {
            let monitoringStatus: PortfolioMonitoringStatusModel = new PortfolioMonitoringStatusModel();
            if (response.subscriptionListDto.length != 0) {
                monitoringStatus.hasSubscription = true;
                monitoringStatus.subscriptionId = response.subscriptionListDto[0].id;
                monitoringStatus.isMonitoringAll = response.subscriptionListDto[0].portfolioList.some(x => x.portfolioId == monitoringStatus.portfolioMonitorAllId);
                monitoringStatus.portfoliosMonitoredIds = response.subscriptionListDto[0].portfolioList.map(x => x.portfolioId);
            }
            ret.next(monitoringStatus);
        });
        return ret;
    }

    public updatePortfolioSubscription(id: string, userId: string, accountId: string, portfolioIds: string[]): Observable<Object> {
        this.analyticsService.sendBeacon(new GoogleAnalyticsBeacon('PortfolioMonitoring', 'Portfolio Management', { SubscriptionId: id }));
        let params = {
            id: id,
            userId: userId,
            enabled: true,
            frequency: 1,
            portfolioIds: portfolioIds,
            accountId: accountId
        };
        return this.http.put(this.serverUrl + this.portfolioMonitoringLink, params, { responseType: 'text' });
    }

    public modifyPortfolioSubscription(portfolioInfo:any, monitoringStatus: PortfolioMonitoringStatusModel, userId: string, accountId: string) : Observable<any>
    {
        let ret: Subject<any> = new Subject<any>();
        if (!portfolioInfo.isChecked == true) {
            if (monitoringStatus.hasSubscription) {
                monitoringStatus.portfoliosMonitoredIds = monitoringStatus.portfoliosMonitoredIds.filter(x => x !== portfolioInfo.portfolio.id);
                if (monitoringStatus.portfoliosMonitoredIds.length != 0) {
                    this.updatePortfolioSubscription(monitoringStatus.subscriptionId, userId, accountId,  monitoringStatus.portfoliosMonitoredIds).subscribe(response => {
                        ret.next({response:response, message:"Unsubscribed from alerts successfully"} );
                    });
                }
                else {
                    this.disablePortfolioSubscription(monitoringStatus.subscriptionId, userId, accountId).subscribe(response => {

                        ret.next({response:response, message:"Unsubscribed from alerts successfully"} );
                    });;
                }
            }
        }
        else {
            if (monitoringStatus.portfoliosMonitoredIds != null) {
                monitoringStatus.portfoliosMonitoredIds.push(portfolioInfo.portfolio.id);
                this.updatePortfolioSubscription(monitoringStatus.subscriptionId, userId, accountId, monitoringStatus.portfoliosMonitoredIds).subscribe(response => {
                    ret.next({response:response, message:"Subscribed to alerts successfully"} );
                });
            }
            else {
                monitoringStatus.portfoliosMonitoredIds = [];
                monitoringStatus.portfoliosMonitoredIds.push(portfolioInfo.portfolio.id);
                this.createPortfolioSubscription(userId, accountId, monitoringStatus.portfoliosMonitoredIds).subscribe(response => {
                    ret.next({response:response, message:"Subscribed to alerts successfully"} );
                });
            }
        }
        return ret;
    }

    public disablePortfolioSubscription(id: string, userId: string, accountId: string) {
        let params: HttpParams = new HttpParams();
        params = params.set("id", id)
            .set("userId", userId)
            .set("accountId", accountId);

        return this.http.delete(this.serverUrl + this.portfolioMonitoringLink + '/' + id, { params: params, responseType: 'text' });
    }

    public createPortfolioSubscription(/* id: string, */ userId: string, accountId: string, portfolioIds: string[]): Observable<Object> {
        let body = {
            userId: userId,
            enabled: true,
            frequency: 1,
            portfolioIds: portfolioIds,
            accountId: accountId
        };
        return this.http.post(this.serverUrl + this.portfolioMonitoringLink, body, { responseType: 'text' });
    }

    public updatePortfolioStatus(portfolioId: string, status: string) {
        let patchBody = {
            id: portfolioId,
            sharingStatus: status
        };
        return this.http.patch(this.serverUrl + this.portfolioServiceLink, patchBody, { responseType: 'text' });
    }

    public getPortfolioById(portfolioId: string) {
        let userInfo = StorageService.get().userInfo;
        let params: HttpParams = new HttpParams();
        params = params.set("accountId", userInfo.accountId)
            .set("userId", userInfo.userId);
        return this.http.get<any>(this.serverUrl + this.portfolioServiceLink + '/' + portfolioId, { params: params });
    }

    public updatePortfolioWeight(portfolioId: string, portfolioDetailId: string, newWeightValue: number, isEmptyValue: boolean) {
        let params: HttpParams = new HttpParams();
        params = params.set("portfolioId", portfolioId)
            .set("portfolioDetailId", portfolioDetailId)
            .set("newWeightValue", newWeightValue.toString() == "" ? null : newWeightValue.toString())
            .set("isEmptyValue", isEmptyValue.valueOf().toString());
        return this.http.patch(this.serverUrl + this.portfolioServiceLink, null, { params: params });
    }

    public updatePortfolioWeightPortfolioCreation(portfolioMatchId: string, newWeightValue: number, isUnmatched: boolean) {
        let params: HttpParams = new HttpParams();
        params = params.set("portfolioMatchId", portfolioMatchId)
            .set("newWeightValue", newWeightValue.toString() == "" ? null : newWeightValue.toString())
            .set("isUnmatched", isUnmatched.valueOf().toString());
        return this.http.patch(this.serverUrl + this.portfolioServiceLink, null, { params: params, responseType: 'text' });
    }

    public getPortfolioDetails(portfolioId: string, skip: number, take: number, orderBy: string, orderByAsc: boolean) {
        let userInfo = StorageService.get().userInfo;
        let listOptions: any = {
            skip: skip,
            take: take,
            orderBy: orderBy,
            orderAscending: orderByAsc,
            includeAllFields: true,
            getCount: true
        };

        let params: HttpParams = new HttpParams();
        params = params.set("userId", userInfo.userId);
        params = this.urlEncodeObject(listOptions, params);

        return this.http.get<any>(this.serverUrl + this.portfolioServiceLink + '/' + portfolioId + '/details', { params: params });
    }

    public getSecurities(namePortfolio: string, typeOfMatch: string, skip: number, take: number, orderBy: string, orderByAsc: boolean, sharingStatus: PortfolioSharingStatus): Observable<any> {
        let userInfo = StorageService.get().userInfo;
        let listOptions: any = {
            skip: skip,
            take: take,
            orderBy: orderBy,
            orderAscending: orderByAsc,
            includeAllFields: true,
            getCount: true
        };

        let params: HttpParams = new HttpParams();
        params = params.set('isMyPortfolio', 'true')
            .set('namePortfolio', '')
            .set('sharingStatus', sharingStatus.valueOf().toString())
            .set('portfolioType', '1')
            .set('isNameEqual', 'false')
            .set('newVersion', 'false')
            .set("userId", userInfo.userId)
            .set("accountId", userInfo.accountId);
        params = this.urlEncodeObject(listOptions, params);

        return this.http.get<PortfolioModel>(this.serverUrl + this.portfolioServiceLink + '/' + namePortfolio + "/matches/" + typeOfMatch, { params: params });
    }

    public savePortfolio(filterId: string, portfolioId: string, portfolioName: string, isShared: boolean, update: boolean) {
        let body = {
            filterId: filterId,
            isValid: true,
            portfolioId: portfolioId,
            portfolioName: portfolioName,
            sharingStatus: (isShared ? PortfolioSharingStatus.Shared : PortfolioSharingStatus.Private)
        };

        if (update)
            return this.http.put(this.serverUrl + 'screeningtoolserv/api/v1/portfolios', body, { responseType: 'text' });
        else
            return this.http.post(this.serverUrl + 'screeningtoolserv/api/v1/portfolios', body, { responseType: 'text' });
    }

    public generatePortfolioAnalytics(firstPortfolio: string, secondPortfolio: string, accountId:string, exagoReportName: string): Observable<string> {
        let params: HttpParams = new HttpParams();
        params = params.set('portf1', firstPortfolio)
            .set('portf2', secondPortfolio)
            .set('accountId', accountId)
            .set('reportName', exagoReportName);

        return this.http.get<string>(this.serverUrl + '/portfolioserv/api/v1/portfolios', { params: params });
    }

    public getExagoReportNames(): Observable<string[]> {
        return this.http.get<string[]>(this.serverUrl + '/portfolioserv/api/v1/portfolios');
    }
}